/**
 * @author 徐光标
 * @email
 * @create 2019/11/10
 * excel报表
 */
package cn.easyplatform.studio.web.editors.entity;

import cn.easyplatform.entities.beans.report.JxlsReport;
import cn.easyplatform.lang.Streams;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.utils.StringUtil;
import cn.easyplatform.studio.utils.WebUtils;
import cn.easyplatform.studio.vos.GuideConfigVo;
import cn.easyplatform.studio.web.editors.*;
import cn.easyplatform.studio.web.editors.help.GuideConfigEditor;
import cn.easyplatform.studio.web.editors.support.CodeFormatter;
import cn.easyplatform.studio.web.editors.support.ZulXsdUtil;
import cn.easyplatform.studio.web.layout.WorkbenchController;
import cn.easyplatform.studio.web.views.impl.AbstractView;
import cn.easyplatform.type.EntityType;
import nu.xom.Attribute;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import org.apache.commons.lang3.StringUtils;
import org.zkoss.util.media.Media;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.*;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zss.api.AreaRef;
import org.zkoss.zss.api.Exporters;
import org.zkoss.zss.api.Importers;
import org.zkoss.zss.api.model.Book;
import org.zkoss.zss.ui.Spreadsheet;
import org.zkoss.zul.*;
import org.zkoss.zul.impl.LabelImageElement;

import java.io.*;
import java.util.*;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public class JxlsReportEntityEditor extends AbstractEntityEditor<JxlsReport>
        implements CodeEditor {

    private Textbox entityId; //主键

    private Textbox entityName; //名称

    private Textbox entityDesp; //描述

    private Bandbox entityTable; //数据表

    private Combobox reportFormulaType; //公式类型

    private Spreadsheet spreadsheet; //如果报表类型为Jxls时使用

    private Textbox reportTextBoxArea; //报表区域输入框

    private Rows dataRows; //数据源列表

    private Button reportButtonAddData; //添加数据按钮

    private Button reportButtonAddConditions; //添加条件

    //   private List<DataRowView> dataRowViewList = new ArrayList<>();

    private DataRowView dataRowView;

    private ConditionsRowView conditionsRowView = null;

    @Wire
    private Tree dataBindTree;

    @Wire
    private Treeitem dataBindTreeRoot;

    private Element configData;//报表配置的元素,主树根 不可以为空
    private Element mainElement;//根节点area

    private Menupopup jxls_Popup;

    private Menuitem menuitem_add_a, menuitem_add_b, menuitem_delete;

    private enum Direction {RIGHT, DOWN}


    private final static String AREA_Template_pref="Template!";

    private static String  defaultXls="<xls> \n\t<area ref= \"Template!A1:B1 \"> \n  \n\t </area> \n</xls>";

    /**
     * @param workbench
     * @param entity
     * @param code
     */
    public JxlsReportEntityEditor(WorkbenchController workbench,
                                  JxlsReport entity, char code) {
        super(workbench, entity, code);
    }

    /**
     * 初始化
     *
     * @param args
     */
    @Override
    public void create(Object... args) {
        super.create(args);
        Tabpanel tabpanel = new Tabpanel();
        Idspace is = new Idspace();
        is.setHflex("1");
        is.setVflex("1");
        is.setParent(tabpanel);

        //加载页面
        Executions.createComponents("~./include/editor/entity/jxlsport.zul", is,
                null);

        //初始化控件 && 事件监听
        for (Component comp : is.getFellows()) {
            if (comp.getId().equals("report_textbox_id")) { //主键
                entityId = (Textbox) comp;                              //获取控件引用
                entityId.setValue(entity.getId());                      //设置初始值
                entityId.setReadonly(true);                             //设置只读属性
            } else if (comp.getId().equals("report_textbox_name")) { //名称
                entityName = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                entityName.setValue(entity.getName());
            } else if (comp.getId().equals("report_textbox_desp")) { //描述
                entityDesp = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                entityDesp.setValue(entity.getDescription());
            } else if (comp.getId().equals("report_bandbox_table")) { //数据表
                entityTable = (Bandbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                comp.addEventListener(Events.ON_OPEN, this);
                comp.addEventListener(Events.ON_OK, this);
                comp.getNextSibling().addEventListener(Events.ON_CLICK, this);
                entityTable.setValue(entity.getTable());
            } else if (comp.getId().equals("report_formula_type")) { //公式类型
                reportFormulaType = (Combobox) comp;
                reportFormulaType.setSelectedItem(reportFormulaType.getItemAtIndex(entity.getFormulaType()));
                comp.addEventListener(Events.ON_SELECT, this);
            } else if (comp.getId().equals("report_textbox_area")) { //报表区域
                reportTextBoxArea = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE,this);//值改变时，更新树节点
            } else if (comp.getId().equals("data_rows")) {
                dataRows = (Rows) comp;
            } else if (comp.getId().equals("report_button_add_data")) {
                reportButtonAddData = (Button) comp;
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("report_button_add_conditions")) {
                reportButtonAddConditions = (Button) comp;
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("input_excel")) {
                comp.addEventListener(Events.ON_UPLOAD, this);
            } else if (comp instanceof Button) {
                comp.addEventListener(Events.ON_CLICK, this);
                LabelImageElement xul = (LabelImageElement) comp;

                if (comp.getId().equals("report_config_xml")) {
                    //判断报表格式参数 如果不为空 高亮按钮
                    if (!Strings.isBlank(entity.getConfig())) {
                        xul.setSclass("epeditor-btn-mark");
                    }
                } else if (comp.getId().equals("report_button_customFunctions")) {
                    //判断自定义公式 如果不为空 高亮按钮
                    if (!Strings.isBlank(entity.getCustomFunctions())) {
                        xul.setSclass("epeditor-btn-mark");
                    }
                }
            } else if (comp.getId().equals("fluSpreadsheet")) {
                //excel表格控件
                spreadsheet = (Spreadsheet) comp;
                spreadsheet.setVisible(true);
                spreadsheet.setShowToolbar(true); //工具栏
                spreadsheet.setShowContextMenu(true); //内容菜单
                spreadsheet.setShowFormulabar(true); //公式栏
                spreadsheet.setShowSheetbar(true);
                spreadsheet.setFocus(true);
                spreadsheet.setMaxVisibleColumns(20);
                spreadsheet.setShowAddColumn(true);
                spreadsheet.setShowAddRow(true);

                //设置输入事件监听
                spreadsheet.addEventListener(org.zkoss.zss.ui.event.Events.ON_START_EDITING, this);

                //如果不等于空  将数据库内容 赋值给 spreadsheet
                if (entity.getTemplate() != null) {
                    InputStream inputStream = new ByteArrayInputStream(entity.getTemplate());
                    try {
                        Book book = Importers.getImporter().imports(inputStream, entity.getName());
                        spreadsheet.setBook(book);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    //设置默认模板
                    spreadsheet.setSrc("/web/excel/each_if_demo.xls");
                    //设置默认 配置文件
                    String report1 = Streams.readAndClose(Streams.utf8r(getClass().getResourceAsStream("/web/excel/each_if_demo_1.xml")));
                    entity.setConfig(report1);
                }
            } else if (comp.getId().equals("dataBindTree")) {
                dataBindTree = (Tree) comp;
                dataBindTree.addEventListener(Events.ON_CLICK, treeSelEventListener);
                // dataBindTree.addEventListener(Events.ON_RIGHT_CLICK, treeSelEventListener);
//                        new EventListener<Event>() {
//                    @Override
//                    public void onEvent(Event event) throws Exception {
//
//                        System.out.println("event="+event.getTarget() +"，"+event.getName());
////            if (event.getName().equals(Events.ON_SELECT)) { //修改事件
////                setDirty();
////                entity.setConfig(writeEach(false));
////            } else if (event.getName().equals(Events.ON_CLICK)) {
////                if (event.getTarget() == dataAreaButton) {
////                    spreadsheet.addEventListener(org.zkoss.zss.ui.event.Events.ON_CELL_SELECTION, JxlsReportEntityEditor.this);
////                    spreadsheet.setFocus(true);
////                    spreadsheet.setAttribute("textBox", event.getTarget().getPreviousSibling());
////                } else if (event.getTarget() == delete) {
////                    delete();
////                    // dataRowViewList.remove(DataRowView.this);
////                }
////            }
//                    }
//                });
            } else if (comp.getId().equals("dataBindTreeRoot")) {
                dataBindTreeRoot = (Treeitem) comp;
            } else if (comp.getId().equals("jxls_Popup")) {
                jxls_Popup = (Menupopup) comp;
            } else if (comp.getId().equals("menuitem_add_a")) {
                menuitem_add_a = (Menuitem) comp;
                menuitem_add_a.addEventListener(Events.ON_CLICK, treeSelEventListener);
            } else if (comp.getId().equals("menuitem_add_b")) {
                menuitem_add_b = (Menuitem) comp;
                menuitem_add_b.addEventListener(Events.ON_CLICK, treeSelEventListener);
            } else if (comp.getId().equals("menuitem_delete")) {
                menuitem_delete = (Menuitem) comp;
                menuitem_delete.addEventListener(Events.ON_CLICK, treeSelEventListener);
            }
        }


        //加载数据
        readConfig(entity.getConfig());


        workbench.addEditor(tab, tabpanel);
    }

//    @Listen("onClick = #menuitem_add_a")

    /**
     * 添加节点的数据绑定
     *
     * @param subnode
     */
    private void doAddEach(boolean subnode) {
        Treeitem selItem = dataBindTree.getSelectedItem();


        Element each = newEach("var"+(new Date()).getTime());
        Treeitem tr = getTreeItem(each);

        Element parentEach = null;
        if (selItem == null) {
            if(mainElement==null){
                //未配置config
                createConfigXml();
            }
            parentEach = mainElement;
            dataBindTreeRoot.getTreechildren().appendChild(tr);

        } else {
            if (subnode) {
                parentEach = (Element) selItem.getAttribute("element");
                Treechildren children=selItem.getTreechildren();
                if(children==null){
                    children=new Treechildren();
                    selItem.appendChild(children);
                }
                children.appendChild(tr);
            } else {
                //同级节点
                parentEach = (Element) selItem.getParentItem().getAttribute("element");

                selItem.getParentItem().getTreechildren().appendChild(tr);

            }
            if("each".equals(parentEach.getLocalName())){
                parentEach=parentEach.getFirstChildElement("area");
                //向下追溯到<area>节点
            }


        }

        String pref=parentEach.getAttributeValue("ref");
        each.getAttribute("ref").setValue(pref);
        each.getFirstChildElement("area").getAttribute("ref").setValue(pref);

        parentEach.appendChild(each);
        tr.setSelected(true);
        if (dataRowView == null) {
            dataRowView = new DataRowView(dataRows, tr);
            dataRowView.btnDataSource.addEventListener(Events.ON_CLICK,this);
        } else {
            dataRowView.setData(tr);
        }
        setDirty();
    }

    /**
     * 新增节点对象
     *
     * @return
     */
    private Element newEach(String var) {
        Element each = new Element("each");
        each.addAttribute(new Attribute("items", ""));
        each.addAttribute(new Attribute("var", var));
        each.addAttribute(new Attribute("ref", ""));
        each.addAttribute(new Attribute("dir", ""));
        each.addAttribute(new Attribute("select", ""));
        each.addAttribute(new Attribute("groupBy", ""));
        each.addAttribute(new Attribute("groupOrder", ""));

        Element area = new Element("area");
        area.addAttribute(new Attribute("ref", ""));
        each.appendChild(area);
        return each;
    }



    /**
     * 添加节点的数据绑定
     */
    private void doDeleteEach() {
        Treeitem selEach= dataBindTree.getSelectedItem();
        if(selEach==null){
            return;
        }
        String var=selEach.getLabel();
        WebUtils.showConfirm(var,  new EventListener<Event>() {
            @Override
            public void onEvent(Event event) throws Exception {
                if (event.getName().equals(Events.ON_OK)) {
                    deleteEach();
                }else {
                    return;
                }
            }
        });
    }

    private void deleteEach(){
        Treeitem selEach= dataBindTree.getSelectedItem();
        if(selEach==null){
            return;
        }
        dataBindTree.removeItemFromSelection(selEach);
        Element each=(Element)selEach.getAttribute("element");
        each.getParent().removeChild(each);
        selEach.getParent().removeChild(selEach);
        if (dataRowView != null)
            dataRowView.clearData();
        setDirty();
    }


    private String getReplaceAll(String str) {
        str = str.replaceAll("<", "&lt;");
        str = str.replaceAll(">", "&gt;");
        str = str.replaceAll("\"", "&quot;");
        str = str.replaceAll("'", "&apos;");
        return str;
    }


    /**
     * 保存时,验证数据
     *
     * @return
     */
    @Override
    protected boolean validate() {
        if (Strings.isBlank(entity.getName())) {
            WebUtils.notEmpty(Labels.getLabel("entity.name"));
            return false;
        }
        String dualNode=checkDualNode();
        if(!dualNode.equals("")){
            WebUtils.showError("有重复的变量，请修改："+dualNode);
            return false;
        }

        File tempFile = null;
        try {
            //读取表格数据

            entity.setConfig(configData==null?"":configData.toXML());
            tempFile = File.createTempFile("temp", ".xls");
            Exporters.getExporter().export(spreadsheet.getBook(), tempFile);
            InputStream inputStream = new FileInputStream(tempFile);
            entity.setTemplate(Streams.readBytesAndClose(inputStream));
        } catch (Exception ex) {
            WebUtils.showError(Labels.getLabel("editor.report.save.error",
                    new Object[]{ex.getMessage()}));
            return false;
        } finally {
            tempFile.delete();
        }
        return true;
    }

    private Hashtable<String,String> tmpVarMap;
    /**
     * 检查是否有重复的节点，无返回空，有返回节点var名称
     * @return
     */
    private String checkDualNode(){
        tmpVarMap=new Hashtable<>();
      Elements list= configData.getChildElements();
      return  checkDualNode(list);

    }

    private String checkDualNode(Elements list){
        if(list!=null){
        for(int i=0;i<list.size();i++){
            Element element=list.get(i);
            if("each".equals(element.getLocalName())){
                String var=element.getAttributeValue("var");
                if(tmpVarMap.get(var)==null){
                    tmpVarMap.put(var,"1");
                }else{
                    return var;
                }
            }
             String err=checkDualNode(element.getChildElements());
            if(!"".equals(err)){
                return err;
            }
        }}
        return "";
    }

    /**
     * 处理事件
     *
     * @param evt
     */
    @Override
    protected void dispatch(Event evt) {

        System.out.println(evt.getTarget()  +",do:"+evt.getName());
        //如果触发事件,保存到实体类,并且按钮改为可保存状态
        if (Events.ON_CHANGE.equals(evt.getName()) || Events.ON_CHANGING.equals(evt.getName()) || "onStartEditing".equals(evt.getName()) || Events.ON_SELECT.equals(evt.getName())) {
            Component c = evt.getTarget();
            if (c == entityName) {
                entity.setName(entityName.getValue());
            } else if (c == entityTable) {
                entity.setTable(entityTable.getValue());
            } else if (c == entityDesp) {
                entity.setDescription(entityDesp.getValue());
            } else if (c == reportFormulaType) {
                entity.setFormulaType((Integer.parseInt((String) reportFormulaType.getSelectedItem().getValue())));
            }else if(c==reportTextBoxArea){
                mainElement.getAttribute("ref").setValue("Template!"+reportTextBoxArea.getValue());
            }
//            entity.setConfig(writeEach(false));
            setDirty();
        } else if ("report_button_customFunctions".equals(evt.getTarget().getId())) { //自定义函数事件

            AbstractView.createCodeView(
                    new SimpleEditorCallback(this, (Button) evt.getTarget(), "customFunctions", false), "text/x-plsql", evt.getTarget()).doOverlapped();
        } else if ("report_button_select_area".equals(evt.getTarget().getId())) { //添加 表格选择事件
            spreadsheet.addEventListener(org.zkoss.zss.ui.event.Events.ON_CELL_SELECTION, this);
            spreadsheet.setFocus(true);
            spreadsheet.setAttribute("textBox", evt.getTarget().getPreviousSibling());
        } else if ("report_config_xml".equals(evt.getTarget().getId())) { //报表配置事件
            if(configData==null){

                entity.setConfig("");
            }else{
                entity.setConfig(configData.toXML());
            }
            AbstractView.createCodeView(new EditorCallback<String>() {
                @Override
                public String getValue() {
                    return entity.getConfig();
                }

                @Override
                public void setValue(String value) {
                    setDirty();
                    entity.setConfig(value);
                    readConfig(entity.getConfig());
                }

                @Override
                public String getTitle() {
                    return "config";
                }

                @Override
                public Page getPage() {
                    return entityId.getPage();
                }

                @Override
                public Editor getEditor() {
                    return null;
                }
            }, "xml", evt.getTarget()).doOverlapped();
            /*AbstractView.createCodeView(
                    new SimpleEditorCallback(this, (Button) evt.getTarget(), "config", false), "xml", evt.getTarget()).doOverlapped();*/
        } else if ("input_excel".equals(evt.getTarget().getId())) { //导入excel
            UploadEvent uploadEvent = (UploadEvent) evt;
            Media media = uploadEvent.getMedia();
            if ("xls".equals(media.getFormat().toLowerCase()) || "xlsx".equals(media.getFormat().toLowerCase())) {
                try {
                    Book book = Importers.getImporter().imports(media.getStreamData(), media.getName().split("\\.")[0]);
                    spreadsheet.setBook(book);
                    setDirty();
//                    entity.setConfig("");
//                    for (DataRowView d : dataRowViewList) {
//                        d.delete();
//                    }
//                    dataRowViewList.clear();
//                    conditionsRowView.delete();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                WebUtils.showError("不支持上传" + media.getFormat() + "类型的文件");
            }
        } else if ("out_excel".equals(evt.getTarget().getId())) { //导出excel
            Filedownload.save(entity.getTemplate(), "application/vnd.ms-excel", entity.getName());
        } else if (evt.getName().equals(org.zkoss.zss.ui.event.Events.ON_CELL_SELECTION)) {  //当用户选择行/列或单元格范围时  当用户移动或修改选择范围时
            Spreadsheet spreadsheet = (Spreadsheet) evt.getTarget();
            AreaRef areaRef = spreadsheet.getSelection();
            String area = asciiToString(areaRef.getColumn() + 65) + (areaRef.getRow() + 1) + ":" + asciiToString(areaRef.getLastColumn() + 65) + (areaRef.getLastRow() + 1);
            Textbox textbox = (Textbox) spreadsheet.getAttribute("textBox");
            textbox.setFocus(true);
            textbox.setValue(area);

            spreadsheet.removeEventListener(org.zkoss.zss.ui.event.Events.ON_CELL_SELECTION, this);
            if("report_textbox_area".equals(textbox.getId()))
            {
                mainElement.getAttribute("ref").setValue("Template!"+reportTextBoxArea.getValue());
            }
            Object objView= spreadsheet.getAttribute("DataRowView");
            if(objView!=null){
                ((DataRowView)objView).updateTreeItem();
            }

//            entity.setConfig(writeEach(false));
            setDirty(); //高亮保存事件
        } else if ("report_button_add_data".equals(evt.getTarget().getId())) { //添加数据按钮
            addDataRowView();
            //new DataRowView(dataRows);
        } else if ("report_button_add_conditions".equals(evt.getTarget().getId())) { //添加条件判断
            new ConditionsRowView(dataRows);
        }else if(evt.getTarget()==dataRowView.btnDataSource){
             AbstractView.createCodeView(new SimpleSqlEditorCallback(this,dataRowView.each,
                     (Button)evt.getTarget(), "items", true),"text/x-plsql", evt.getTarget()).doOverlapped();
                   // new (this, (Button) evt.getTarget(), "customFunctions", false), "text/x-plsql", evt.getTarget()).doOverlapped();
        } else {
            Component c = evt.getTarget();
            if (evt.getName().equals(Events.ON_OPEN) || evt instanceof KeyEvent) {// Bandbox
                if (c == entityTable) {
                    if (evt instanceof OpenEvent) {
                        ((Bandbox) c).setValue(((OpenEvent) evt).getValue() + "");
                    }
                    AbstractView.createEntityView(
                            new BandboxCallback(this, (Bandbox) c), EntityType.TABLE.getName(), c)
                            .doOverlapped();
                } else {
                    if (evt instanceof OpenEvent) {
                        ((Bandbox) c).setValue(((OpenEvent) evt).getValue() + "");
                    }
                    AbstractView.createEntityView(
                            new BandboxCallback(this, (Bandbox) c),
                            EntityType.LOGIC.getName(), c).doOverlapped();
                }
            } else {
                c = c.getPreviousSibling();
                if (c == entityTable) {
                    if (!Strings.isBlank(entityTable.getValue()))
                        openEditor(evt.getTarget(), entityTable.getValue());
                }
            }
        }
    }

    /**
     * 读取报表的数据源配置
     *
     * @param config
     */
    private void readConfig(String config) {
        if (config == null || "".equals(config.trim())) {
            return;
        }
        nu.xom.Document document = ZulXsdUtil.buildDocument(config);

        //配置文件格式转换
        configData = document.getRootElement();
        //取出报表区域
        mainElement = configData.getChildElements("area").get(0);
        reportTextBoxArea.setValue(mainElement.getAttributeValue("ref").replace("Template!", "")); //报表区域

        //取出主数据区域
        // readEach(mainElement);
        //  System.out.println("configData:"+configData.toXML());
        dataBindTreeRoot.getChildren().clear();
        readDataBindTree(mainElement);
    }

    private void createConfigXml(){
        readConfig(defaultXls);
    }

    private void readDataBindTree(Element element) {
        // Treeitem treeItem = getTreeItem(element);
        dataBindTreeRoot.setAttribute("element", element);
        // dataBindTree
        loadTreeNode(element, dataBindTreeRoot);
    }

    /**
     * 数据源绑定的树模板数据
     */
    private void loadTreeNode(Element element, Treeitem treeitem) {
        Elements eachs = element.getChildElements("each");
        if (eachs != null)
            for (int i = 0; i < eachs.size(); i++) {
                Element each = eachs.get(i);
                Treeitem eachnode = getTreeItem(each);
                //树的子节点在<area> 下
                Element area = each.getChildElements("area").get(0);



                Treechildren subChildren = treeitem.getTreechildren();
                if (subChildren == null) {
                    subChildren = new Treechildren();
                    treeitem.appendChild(subChildren);
                }
                subChildren.appendChild(eachnode);

//                loadTreeNode(each, eachnode);
                loadTreeNode(area,eachnode);
            }
    }

    private Treeitem getTreeItem(Element element) {
        Treeitem item = new Treeitem();
        Treerow tr = new Treerow();
        String varId = element.getAttributeValue("var");
        Treecell cell1 = new Treecell(varId);
        Treecell cell2 = new Treecell(element.getAttributeValue("description"));

        //item.setId(varId);
        item.setAttribute("ref", element.getAttributeValue("ref"));

        tr.appendChild(cell1);
        tr.appendChild(cell2);
        tr.setTooltiptext("变量名："+varId);

        item.appendChild(tr);
        item.setAttribute("element", element);
        return item;
    }

    /**
     * 更新树节点的显示
     *
     * @param treeNode
     * @param element
     */
    private void updateEachTreeNode(Treeitem treeNode, Element element) {
        treeNode.setAttribute("element", element);
        Treerow treeRow = treeNode.getTreerow();
        String var = element.getAttributeValue("var");
       // treeRow.setId(var);
        ((Treecell) treeRow.getChildren().get(0)).setLabel(var);
        ((Treecell) treeRow.getChildren().get(1)).setLabel(element.getAttributeValue("description"));
        treeRow.setTooltiptext("变量名："+var);
    }

    /**
     * 新增，默认为根节点，看用户选择的节点，提示确认
     */
    private void addDataRowView() {
        doAddEach(false);

    }

//    /**
//     * 递归读取配置信息
//     */
//    private void readEach(Element element) {
//        Elements eachs = element.getChildElements("each");
//        if (eachs.size() > 0) {
//            Element each = eachs.get(0);
//
//            new DataRowView(dataRows, each.getAttributeValue("items"), each.getAttributeValue("var"), each.getAttributeValue("ref").replace("Template!", ""), each.getAttributeValue("dir"), each.getAttributeValue("select"), each.getAttributeValue("groupBy"), each.getAttributeValue("groupOrder"));
//            if (each.getChildElements("area").size() > 0) {
//                Element area = each.getChildElements("area").get(0);
//                readEach(area);
//            }
//        } else if (element.getChildElements("if").size() > 0) {
//            Element elementIF = element.getChildElements("if").get(0);
//            Elements expressions = elementIF.getChildElements("area");
//            String expression1, expression2;
//            if ("true".equals(expressions.get(0).getAttributeValue("clearCells"))) {
//                expression1 = expressions.get(0).getAttributeValue("ref");
//                expression2 = expressions.get(1).getAttributeValue("ref");
//            } else {
//                expression1 = expressions.get(1).getAttributeValue("ref");
//                expression2 = expressions.get(0).getAttributeValue("ref");
//            }
//            new ConditionsRowView(dataRows, elementIF.getAttributeValue("condition"), elementIF.getAttributeValue("ref").replaceAll("Template!", ""), expression1.replaceAll("Template!", ""), expression2.replaceAll("Template!", ""));
//        }
//    }

//    /**
//     * 读取页面上的配置数据信息
//     *
//     * @param isCheck 是否检核数据格式
//     * @return
//     */
//    @Deprecated
//    private String writeEach(Boolean isCheck) {
//        return configData.toXML();
//    }

    /**
     * 重绘源码
     */
    protected void refreshSource() {
    }

    @Override
    public void insertTodo() {
        if(source!=null)
        source.insertText("<!-- TODO -->");
    }

    @Override
    public void insertComments() {
        if(source!=null)
        source.insertText("<!-- This is a comment -->");
    }

    @Override
    public void undo() {
        if(source!=null)
        source.exeCmd("undo");
    }

    @Override
    public void redo() {
        if(source!=null)
        source.exeCmd("redo");
    }

    @Override
    public void selectAll() {
        if(source!=null)
        source.exeCmd("selectAll");
    }

    @Override
    public void format() {
        if(source!=null)
        source.exeCmd("format");
    }

    @Override
    public void formatAll() {
        if(source!=null)
        source.exeCmd("formatAll");
    }

    @Override
    public void deleteLine() {
        if(source!=null)
        source.exeCmd("deleteLine");
    }

    @Override
    public void indentMore() {
        if(source!=null)
        source.exeCmd("indentMore");
    }

    @Override
    public void indentLess() {
        if(source!=null)
        source.exeCmd("indentLess");
    }

    @Override
    public void find() {
        if(source!=null)
        source.exeCmd("find");
    }

    @Override
    public void findNext() {
        if(source!=null)
        source.exeCmd("findNext");
    }

    @Override
    public void findPrev() {
        if(source!=null)
        source.exeCmd("findPrev");
    }

    @Override
    public void replace() {
        if(source!=null)
        source.exeCmd("replace");
    }

    @Override
    public void replaceAll() {
        if(source!=null)
        source.exeCmd("replaceAll");
    }

    /**
     * 将字符串转成ASCII
     *
     * @param value
     * @return
     */
    public String stringToAscii(String value) {
        StringBuilder sbu = new StringBuilder();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]).append(",");
            } else {
                sbu.append((int) chars[i]);
            }
        }
        return sbu.toString();
    }

    /**
     * 将ASCII转成字符串的
     *
     * @param ascii
     * @return
     */
    public String asciiToString(int ascii) {
        return String.valueOf((char) ascii);
    }

    /**
     * 选择树的数据源--》可以进行修改
     */
    private void doSelectEach() {
        //  System.out.println("doSelectEach"+dataBindTree.getSelectedItem().getId());
        Treeitem selItem = dataBindTree.getSelectedItem();

        if(selItem==null){
            return;
        }

        if (dataRowView == null) {
            dataRowView = new DataRowView(dataRows, selItem);
            dataRowView.btnDataSource.addEventListener(Events.ON_CLICK,this);
        } else {
            dataRowView.setData(selItem);
        }

    }

    /**
     * 新建一个空的area
     * @return
     */
    private Element newArea(){
        Element area=new Element("area");
        area.addAttribute(new Attribute("ref",""));
    return area;
    }

    /**
     * 变量绑定树的选择监听
     *
     * @param event
     * @throws Exception
     */
    EventListener<Event> treeSelEventListener = new EventListener<Event>() {
        @Override
        public void onEvent(Event event) throws Exception {
            Component eventTarget = event.getTarget();
            if (eventTarget == dataBindTree) {

                doSelectEach();

            } else if (eventTarget == menuitem_add_a) {
                doAddEach(false);
            } else if (eventTarget == menuitem_add_b) {
                doAddEach(true);
            } else if (eventTarget == menuitem_delete) {
                doDeleteEach();
                // doAdd();
            }

        }
    };

    /**
     * 数据源布局
     */
    class DataRowView {
        Textbox dataSource; //数据源
        Textbox displayName; //对象名称
        Textbox description;//数据说明
        Textbox dataArea; //数据区域
        Textbox groupByTextBox; //分组依据
        Textbox groupOrderTextBox; //分组
        Textbox filtration; //过滤
        Button dataAreaButton; //选择区域按钮
        Combobox reportDirection; //报表方向

        Button btnDataSource=new Button();
//         <button iconSclass="z-icon-scribd"
//        sclass="epeditor-btn" id="report_config_xml"/>
        A delete;
        Group group;

        String getDataSource() {
            return getReplaceAll(dataSource.getValue());
        }

        String getDisplayName() {
            return getReplaceAll(displayName.getValue());
        }

        String getDataArea() {
            return getReplaceAll(dataArea.getValue());
        }

        String getGroupBy() {
            return getReplaceAll(groupByTextBox.getValue());
        }

        String getGroupOrder() {
            return getReplaceAll(groupOrderTextBox.getValue());
        }

        String getFiltration() {
            return getReplaceAll(filtration.getValue());
        }

        Element each;
        Treeitem treeitem;

        /**
         * @param component
         */
        public DataRowView(Component component) {
            this(component, "", "", "", "", "", "", "");
        }

        public DataRowView(Component component, Treeitem treeitem) {
            this(component, "", "", "", "", "", "", "");
            this.treeitem = treeitem;
            this.each = (Element) this.treeitem.getAttribute("element");
            reloadData();
        }

        /**
         * @param component  拼接在哪个布局下
         * @param source     数据源
         * @param name       变量名
         * @param area       数据区域
         * @param direction  报表方向
         * @param select     筛选
         * @param groupBy    分组依据
         * @param groupOrder 分组条件
         */
        public DataRowView(Component component, String source, String name, String area, String direction, String select, String groupBy, String groupOrder) {
            group = new Group(Labels.getLabel("entity.report.config.data") + "绑定");
            // 第一个打开
            group.setOpen(true);
            group.setParent(component);
            group.setAttribute("type", "DataRowView");
            Hlayout hlayout = new Hlayout();
            hlayout.setHflex("1");

//            //删除按钮
//            if (!"report_data_rows".equals(component.getId())) {
//                delete = new A();
//                delete.setLabel(Labels.getLabel("button.delete"));
//                delete.setIconSclass("z-icon-times");
//                delete.setSclass("pull-right");
//                delete.setParent(hlayout);
//                delete.addEventListener(Events.ON_CLICK, eventEventListener);
//                hlayout.setParent(group);
//            }

            Row row;
            Label label;

            // 变量名
            row = new Row();
            label = new Label("变量名");
            label.setParent(row);
            displayName = new Textbox(name);
            displayName.setHflex("1");
            displayName.setParent(row);
            displayName.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);
            //说明
            row = new Row();
            label = new Label("变量说明");
            label.setParent(row);
            description = new Textbox("");
            description.setHflex("1");
            description.setParent(row);
            description.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);




            // 数据源
            row = new Row();
            label = new Label(Labels.getLabel("entity.table.db"));
            label.setParent(row);
            btnDataSource.setIconSclass("z-icon-scribd");
            btnDataSource.setSclass("epeditor-btn");
            btnDataSource.setTooltiptext(source);
           // btnDataSource.addEventListener(Events.ON_CLICK,eventEventListener);
            row.appendChild(btnDataSource);

//            z-icon-scribd.    <button iconSclass="z-icon-scribd"
//        sclass="epeditor-btn" id="report_config_xml"/>

            dataSource = new Textbox(source);
//            dataSource.setRows(3);
//            dataSource.setHflex("1");
//            dataSource.setParent(row);
//            dataSource.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);


            // 数据区域
            row = new Row();
            label = new Label(Labels.getLabel("entity.report.config.data.area"));
            label.setParent(row);
            Div div = new Div();
            div.setParent(row);

            dataArea = new Textbox(area);
            dataArea.setHflex("1");
            dataArea.setParent(div);
            dataArea.addEventListener(Events.ON_CHANGE, eventEventListener);
            dataArea.addEventListener(Events.ON_CHANGING,eventEventListener);
            dataAreaButton = new Button(Labels.getLabel("entity.report.config.select"));
            dataAreaButton.setIconSclass("z-icon-mouse-pointer");
            dataAreaButton.setHflex("1");
            dataAreaButton.setParent(div);
            dataAreaButton.setAttribute("type", "dataAreaButton");
            dataAreaButton.addEventListener(Events.ON_CLICK, eventEventListener);
            row.setParent(component);

            //分组
            row = new Row();
            label = new Label("分组条件");
            label.setParent(row);
            groupOrderTextBox = new Textbox(groupOrder);
            groupOrderTextBox.setHflex("1");
            groupOrderTextBox.setParent(row);
            groupOrderTextBox.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);

            //分组依据
            row = new Row();
            label = new Label("分组依据");
            label.setParent(row);
            groupByTextBox = new Textbox(groupBy);
            groupByTextBox.setHflex("1");
            groupByTextBox.setParent(row);
            groupByTextBox.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);

            //过滤条件  表达式，返回true输出，返回false不输出
            row = new Row();
            label = new Label("过滤条件");
            label.setParent(row);
            filtration = new Textbox(select);
            filtration.setHflex("1");
            filtration.setParent(row);
            filtration.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);

            //报表方向
            row = new Row();
            label = new Label("数据方向");
            label.setParent(row);

            reportDirection = new Combobox(area);
            reportDirection.setHflex("1");
            reportDirection.setParent(row);
            reportDirection.addEventListener(Events.ON_SELECT, eventEventListener);
            //添加选项
            Comboitem comboitem = new Comboitem("纵向");
            comboitem.setValue(JxlsReportEntityEditor.Direction.DOWN);
            reportDirection.appendChild(comboitem);
            //添加选项
            comboitem = new Comboitem("横向");
            comboitem.setValue(JxlsReportEntityEditor.Direction.RIGHT);
            reportDirection.appendChild(comboitem);

            if ("RIGHT".equals(direction)) {
                reportDirection.setSelectedIndex(1);
            } else {
                reportDirection.setSelectedIndex(0);
            }
            row.setParent(component);


        }

//        private void delete() {
//            group.detach();
//            dataSource.getParent().detach();
//            displayName.getParent().detach();
//            dataArea.getParent().getParent().detach();
//            reportDirection.getParent().detach();
//            groupByTextBox.getParent().detach();
//            groupOrderTextBox.getParent().detach();
//            filtration.getParent().detach();
//        }

        /**
         * 清除数据
         */
        private void clearData() {
            dataSource.setValue(""); //数据源
            displayName.setValue("");
            ; //对象名称
            dataArea.setValue("");
            ; //数据区域
            groupByTextBox.setValue("");
            ; //分组依据
            groupOrderTextBox.setValue("");
            ; //分组
            filtration.setValue("");
            ; //过滤

        }

        private void setData(Treeitem item) {
            this.treeitem = item;
            this.each = (Element) this.treeitem.getAttribute("element");
            reloadData();
        }

        private void reloadData() {
            if (each == null) {
                return;
            }

            //    each.getAttributeValue("items"), each.getAttributeValue("var"), each.getAttributeValue("ref").replace("Template!", ""), each.getAttributeValue("dir"), each.getAttributeValue("select"), each.getAttributeValue("groupBy"), each.getAttributeValue("groupOrder")
            String datasql=each.getAttributeValue("items");
            dataSource.setValue(each.getAttributeValue("items")); //数据源
            displayName.setValue(each.getAttributeValue("var"));

            description.setValue(each.getAttributeValue("description"));

            ; //对象名称
            dataArea.setValue(each.getAttributeValue("ref").replace("Template!", ""));
            ; //数据区域
            filtration.setValue(each.getAttributeValue("select"));
            ; //分组依据
            groupByTextBox.setValue(each.getAttributeValue("groupBy"));
            ; //分组
            groupOrderTextBox.setValue(each.getAttributeValue("groupOrder"));
            ; //过滤

            btnDataSource.setTooltiptext(datasql);

            btnDataSource.setSclass(StringUtils.isBlank(datasql)?"epeditor-btn":"epeditor-btn-mark");

        }

        /**
         * 编辑时，更新树节点的element数据和树结构
         */
        protected void updateTreeItem() {
            each.getAttribute("items").setValue(dataSource.getValue());
            each.getAttribute("var").setValue(displayName.getValue());
            each.getAttribute("ref").setValue("Template!" + dataArea.getValue());

            Attribute attDesc= each.getAttribute("description");
            if(attDesc!=null){
                attDesc.setValue(description.getValue());
            }else{
                each.addAttribute(new Attribute("description",description.getValue()));
            }

//            each.addAttribute(new Attribute("dir",""));
            if (each.getAttribute("select") != null)
                each.getAttribute("select").setValue(filtration.getValue());
            else{
                each.addAttribute(new Attribute("select",filtration.getValue()));
            }
            if (each.getAttribute("groupBy") != null){
                each.getAttribute("groupBy").setValue(groupByTextBox.getValue());}
            else{
                each.addAttribute(new Attribute("groupBy",groupByTextBox.getValue()));
            }

            if (each.getAttribute("groupOrder") != null){
                each.getAttribute("groupOrder").setValue(groupOrderTextBox.getValue());}
            else{
                each.addAttribute(new Attribute("groupOrder",groupOrderTextBox.getValue()));
            }



            each.getFirstChildElement("area").getAttribute("ref").setValue("Template!" + dataArea.getValue());

            updateEachTreeNode(treeitem, each);

        }

        /**
         * 内部点击事件
         *
         * @param event
         * @throws Exception
         */
        EventListener<Event> eventEventListener = new EventListener<Event>() {
            @Override
            public void onEvent(Event event) throws Exception {
                if (event.getName().equals(Events.ON_CHANGE) ||event.getName().equals(Events.ON_CHANGING) || event.getName().equals(Events.ON_SELECT)) { //修改事件
                    setDirty();
                    updateTreeItem();
//                    entity.setConfig(writeEach(false));
                } else if (event.getName().equals(Events.ON_CLICK)) {
                    if (event.getTarget() == dataAreaButton) {
                        spreadsheet.addEventListener(org.zkoss.zss.ui.event.Events.ON_CELL_SELECTION, JxlsReportEntityEditor.this);
                        spreadsheet.setFocus(true);
                        spreadsheet.setAttribute("textBox", event.getTarget().getPreviousSibling());
                        spreadsheet.setAttribute("DataRowView",dataRowView);
                    }


//                    else if (event.getTarget() == delete) {
//                       doDeleteEach();
//                        // dataRowViewList.remove(DataRowView.this);
//                    }
                }
            }
        };
    }

    /**
     * 添加逻辑判断布局
     */
    class ConditionsRowView {
        Textbox conditions; //条件
        Textbox area; //区域
        Textbox expression1; //表达式1 (满足时)
        Textbox expression2; //表达式1 (不满足时)
        Button dataAreaButton; //选择区域按钮
        A delete;
        Group group;

        public String getConditions() {
            return getReplaceAll(conditions.getValue());
        }

        public String getExpression1() {
            return getReplaceAll(expression1.getValue());
        }

        public String getExpression2() {
            return getReplaceAll(expression2.getValue());
        }

        public String getArea() {
            return area.getValue();
        }

        /**
         * @param component
         */
        public ConditionsRowView(Component component) {
            this(component, "", "", "", "");

        }

        /**
         * @param component
         * @param conditionsStr
         * @param expression1Str
         * @param expression2Str
         */
        public ConditionsRowView(Component component, String conditionsStr, String areaStr, String expression1Str, String expression2Str) {

            group = new Group("条件");
            // 默认打开
            group.setOpen(true);
            group.setParent(component);
            group.setAttribute("type", "ConditionsRowView");
            Hlayout hlayout = new Hlayout();
            hlayout.setHflex("1");
            delete = new A();
            delete.setLabel(Labels.getLabel("button.delete"));
            delete.setIconSclass("z-icon-times");
            delete.setSclass("pull-right");
            delete.setParent(hlayout);
            delete.addEventListener(Events.ON_CLICK, eventEventListener);
            hlayout.setParent(group);

            Row row;
            Label label;


            row = new Row();
            label = new Label(Labels.getLabel("entity.list.condition"));
            label.setParent(row);
            conditions = new Textbox(conditionsStr);
            conditions.setHflex("1");
            conditions.setParent(row);
            conditions.addEventListener(Events.ON_CHANGE, eventEventListener);
            row.setParent(component);

            //区域
            row = new Row();
            label = new Label(Labels.getLabel("entity.report.config.area"));
            label.setParent(row);

            Div div = new Div();
            div.setParent(row);
            area = new Textbox(areaStr);
            area.setHflex("1");
            area.setParent(div);
            area.addEventListener(Events.ON_CHANGE, eventEventListener);

            dataAreaButton = new Button(Labels.getLabel("entity.report.config.select"));
            dataAreaButton.setIconSclass("z-icon-mouse-pointer");
            dataAreaButton.setHflex("1");
            dataAreaButton.setParent(div);
            dataAreaButton.setAttribute("type", "dataAreaButton");
            dataAreaButton.addEventListener(Events.ON_CLICK, eventEventListener);
            row.setParent(component);

            //条件成立
            row = new Row();
            label = new Label(Labels.getLabel("entity.report.config.condition.true"));
            label.setParent(row);

            div = new Div();
            div.setParent(row);
            expression1 = new Textbox(expression1Str);
            expression1.setHflex("1");
            expression1.setParent(div);
            expression1.addEventListener(Events.ON_CHANGE, eventEventListener);

            dataAreaButton = new Button(Labels.getLabel("entity.report.config.select"));
            dataAreaButton.setIconSclass("z-icon-mouse-pointer");
            dataAreaButton.setHflex("1");
            dataAreaButton.setParent(div);
            dataAreaButton.setAttribute("type", "dataAreaButton");
            dataAreaButton.addEventListener(Events.ON_CLICK, eventEventListener);
            row.setParent(component);

            //条件不成立
            row = new Row();
            label = new Label(Labels.getLabel("entity.report.config.condition.false"));
            label.setParent(row);

            div = new Div();
            div.setParent(row);
            expression2 = new Textbox(expression2Str);
            expression2.setHflex("1");
            expression2.setParent(div);
            expression2.addEventListener(Events.ON_CHANGE, eventEventListener);


            dataAreaButton = new Button(Labels.getLabel("entity.report.config.select"));
            dataAreaButton.setIconSclass("z-icon-mouse-pointer");
            dataAreaButton.setHflex("1");
            dataAreaButton.setAttribute("type", "dataAreaButton");
            dataAreaButton.setParent(div);
            dataAreaButton.addEventListener(Events.ON_CLICK, eventEventListener);
            row.setParent(component);

            reportButtonAddData.setDisabled(true);
            reportButtonAddConditions.setDisabled(true);

            conditionsRowView = this;
        }

        private void delete() {
            group.detach();
            conditions.getParent().detach();
            expression1.getParent().getParent().detach();
            expression2.getParent().getParent().detach();
            area.getParent().getParent().detach();
            conditionsRowView = null;
        }

        /**
         * 内部点击事件
         *
         * @param event
         * @throws Exception
         */
        EventListener<Event> eventEventListener = new EventListener<Event>() {
            @Override
            public void onEvent(Event event) throws Exception {

                if (event.getName().equals(Events.ON_CHANGE) || event.getName().equals(Events.ON_SELECT)) { //修改事件
                    setDirty();
                    // entity.setConfig(writeEach(false));
                } else if (event.getName().equals(Events.ON_CLICK)) {
                    if ("dataAreaButton".equals(event.getTarget().getAttribute("type"))) {
                        spreadsheet.addEventListener(org.zkoss.zss.ui.event.Events.ON_CELL_SELECTION, JxlsReportEntityEditor.this);
                        spreadsheet.setFocus(true);
                        spreadsheet.setAttribute("textBox", event.getTarget().getPreviousSibling());
                    } else if (event.getTarget() == delete) {
                        delete();
                        reportButtonAddData.setDisabled(false);
                        reportButtonAddConditions.setDisabled(false);
                    }
                }
            }
        };
    }
}


class CategoryTreeNode extends DefaultTreeNode<Category> {
    private static final long serialVersionUID = 1L;
    int count;

    public CategoryTreeNode(Category category, int count) {
        super(category, new LinkedList<TreeNode<Category>>()); // assume not a leaf-node
        this.count = count;
    }

    public String getDescription() {
        return getData().getDescription();
    }

    public int getCount() {
        return count;
    }

    public boolean isLeaf() {
        return getData() != null && getData().getChildren().isEmpty();
    }
}

class Category {

    String name;

    String description;

    List children;

    public Category(String name, String desc) {
        this.name = name;
        this.description = desc;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List getChildren() {
        return children;
    }

    public void setChildren(List children) {
        this.children = children;
    }
}
